Improved error handling in xend and XendClient.
40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/python/xen/xend/XendDomain.py
40c9c468bbKq3uC7_fuNUkiMMjArdw tools/python/xen/xend/XendDomainConfig.py
40c9c4685ykq87_n1kVUbMr9flx9fg tools/python/xen/xend/XendDomainInfo.py
+40f50d99YiiaMI1fZBh1VCDFLD57qg tools/python/xen/xend/XendError.py
40c9c46854nsHmuxHQHncKk5rAs5NA tools/python/xen/xend/XendMigrate.py
40c9c468M96gA1EYDvNa5w5kQNYLFA tools/python/xen/xend/XendNode.py
40c9c4686jruMyZIqiaZRMiMoqMJtg tools/python/xen/xend/XendRoot.py
from StringIO import StringIO
import urlparse
+from twisted.protocols import http
+
from encode import *
import sxp
import PrettyPrint
resp = conn.getresponse()
if DEBUG: print resp.status, resp.reason
if DEBUG: print resp.msg.headers
- if resp.status in [204, 404]:
+ if resp.status in [ http.NO_CONTENT ]:
return None
- if resp.status not in [200, 201, 202, 203]:
+ if resp.status not in [ http.OK, http.CREATED, http.ACCEPTED ]:
raise XendError(resp.reason)
pin = sxp.Parser()
data = resp.read()
val = pin.get_val()
#if isinstance(val, types.ListType) and sxp.name(val) == 'val':
# val = val[1]
- if isinstance(val, types.ListType) and sxp.name(val) == 'err':
+ if isinstance(val, types.ListType) and sxp.name(val) == 'xend.err':
raise XendError(val[1])
if DEBUG: print '**val='; sxp.show(val); print
return val
import XendConsole
import XendMigrate
import EventServer
+from XendError import XendError
from xen.xend.server import SrvDaemon
xend = SrvDaemon.instance()
dom = int(id)
dominfo = self.domain_get(dom)
if not dominfo:
- raise ValueError("Invalid domain: " + str(id))
+ raise XendError("Invalid domain: " + str(id))
if dominfo.config:
- raise ValueError("Domain already configured: " + str(id))
+ raise XendError("Domain already configured: " + str(id))
def fn(dominfo):
self._add_domain(dominfo.id, dominfo)
return dominfo
dom = int(dom)
dominfo = self.domain_get(dom)
if not dominfo:
- raise ValueError("invalid domain:" + str(dom))
+ raise XendError("invalid domain:" + str(dom))
self.refresh_schedule()
return dominfo.device_create(devconfig)
dom = int(dom)
dominfo = self.domain_get(dom)
if not dominfo:
- raise ValueError("invalid domain:" + str(dom))
+ raise XendError("invalid domain:" + str(dom))
self.refresh_schedule()
return dominfo.device_destroy(type, idx)
import server.SrvDaemon
xend = server.SrvDaemon.instance()
+from XendError import VmError
+
"""Flag for a block device backend domain."""
SIF_BLK_BE_DOMAIN = (1<<4)
"""
return shutdown_reasons.get(code, "?")
-class VmError(ValueError):
- """Vm construction error."""
-
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
- return self.value
-
-
def blkdev_name_to_number(name):
"""Take the given textual block-device name (e.g., '/dev/sda1',
'hda') and return the device number used by the OS. """
self.autorestart = 1
self.configure_backends()
image = sxp.child_value(config, 'image')
+ if image is None:
+ raise VmError('missing image')
image_name = sxp.name(image)
+ if image_name is None:
+ raise VmError('missing image name')
image_handler = get_image_handler(image_name)
if image_handler is None:
raise VmError('unknown image type: ' + image_name)
--- /dev/null
+
+class XendError(ValueError):
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return self.value
+
+class VmError(XendError):
+ """Vm construction error."""
+
+ pass
+
from twisted.internet import defer
#defer.Deferred.debug = 1
from twisted.internet import reactor
+from twisted.protocols import http
from twisted.web import error
from twisted.web import resource
from twisted.web import server
from xen.xend import sxp
from xen.xend import PrettyPrint
+from xen.xend.Args import ArgError
+from xen.xend.XendError import XendError
def uri_pathlist(p):
"""Split a path into a list.
"""
op = req.args.get('op')
if op is None or len(op) != 1:
- req.setResponseCode(404, "Invalid")
+ req.setResponseCode(http.NOT_ACCEPTABLE, "Invalid request")
return ''
op = op[0]
op_method = self.get_op_method(op)
if op_method is None:
- req.setResponseCode(501, "Not implemented")
+ req.setResponseCode(http.NOT_IMPLEMENTED, "Operation not implemented: " + op)
req.setHeader("Content-Type", "text/plain")
- req.write("Not implemented: " + op)
+ req.write("Operation not implemented: " + op)
return ''
else:
+ return self._perform(op, op_method, req)
+
+ def _perform(self, op, op_method, req):
+ try:
val = op_method(op, req)
- if isinstance(val, defer.Deferred):
- val.addCallback(self._cb_perform, req, 1)
- return server.NOT_DONE_YET
- else:
- self._cb_perform(val, req, 0)
- return ''
+ except Exception, err:
+ return self._perform_err(err, req)
+
+ if isinstance(val, defer.Deferred):
+ val.addCallback(self._perform_cb, req, dfr=1)
+ val.addErrback(self._perform_err, req, dfr=1)
+ return server.NOT_DONE_YET
+ else:
+ self._perform_cb(val, req, 0)
+ return ''
- def _cb_perform(self, val, req, dfr):
+ def _perform_cb(self, val, req, dfr):
"""Callback to complete the request.
May be called from a Deferred.
+
+ @param err: the error
+ @param req: request causing the error
+ @param dfr: deferred flag
"""
if isinstance(val, error.ErrorPage):
req.write(val.render(req))
elif self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(val, req)
+ sxp.show(val, out=req)
else:
req.write('<html><head></head><body>')
self.print_path(req)
if dfr:
req.finish()
+ def _perform_err(self, err, req, dfr=0):
+ """Error callback to complete a request.
+ May be called from a Deferred.
+
+ @param err: the error
+ @param req: request causing the error
+ @param dfr: deferred flag
+ """
+ if not (isinstance(err, ArgError) or
+ isinstance(err, sxp.ParseError) or
+ isinstance(err, XendError)):
+ if dfr:
+ return err
+ else:
+ raise
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(['xend.err', str(err)], out=req)
+ else:
+ req.setHeader("Content-Type", "text/plain")
+ req.write('Error in ')
+ req.write(op)
+ req.write(': ')
+ req.write(str(err))
+ if dfr:
+ req.finish()
+
+
def print_path(self, req):
"""Print the path with hyperlinks.
"""
return self.perform(req)
def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(self.info.sxpr(), out=req)
- else:
- req.write('<html><head></head><body>')
- self.print_path(req)
- #self.ls()
- req.write('<p>%s</p>' % self.info)
- req.write('<p><a href="%s">Connect to domain %d</a></p>'
- % (self.info.uri(), self.info.dom2))
- self.form(req)
- req.write('</body></html>')
- return ''
+ try:
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(self.info.sxpr(), out=req)
+ else:
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ #self.ls()
+ req.write('<p>%s</p>' % self.info)
+ req.write('<p><a href="%s">Connect to domain %d</a></p>'
+ % (self.info.uri(), self.info.dom2))
+ self.form(req)
+ req.write('</body></html>')
+ return ''
+ except Exception, ex:
+ self._perform_err(ex, req)
def form(self, req):
req.write('<form method="post" action="%s">' % req.prePathURL())
return v
def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- self.ls_console(req, 1)
- else:
- req.write("<html><head></head><body>")
- self.print_path(req)
- self.ls(req)
- self.ls_console(req)
- #self.form(req.wfile)
- req.write("</body></html>")
- return ''
+ try:
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ self.ls_console(req, 1)
+ else:
+ req.write("<html><head></head><body>")
+ self.print_path(req)
+ self.ls(req)
+ self.ls_console(req)
+ #self.form(req.wfile)
+ req.write("</body></html>")
+ return ''
+ except Exception, ex:
+ self._perform_err(ex, req)
def ls_console(self, req, use_sxp=0):
url = req.prePathURL()
from xen.xend import PrettyPrint
from xen.xend import EventServer
eserver = EventServer.instance()
+from xen.xend.XendError import XendError
from xen.xend.server import SrvServer
"""
print name, req
dom = sxp.child_value(req, 'domain')
- if not dom: raise ValueError('Missing domain')
+ if not dom: raise XendError('Missing domain')
dom = int(dom)
console_port = sxp.child_value(req, 'console_port')
if console_port:
def op_console_disconnect(self, name, req):
id = sxp.child_value(req, 'id')
if not id:
- raise ValueError('Missing console id')
+ raise XendError('Missing console id')
id = int(id)
console = self.daemon.get_console(id)
if not console:
- raise ValueError('Invalid console id')
+ raise XendError('Invalid console id')
if console.conn:
console.conn.loseConnection()
return ['ok']
return 'op_' + name.replace('.', '_')
def operror(self, name, req):
- raise NotImplementedError('Invalid operation: ' +name)
+ raise XendError('Invalid operation: ' +name)
def dispatch(self, req):
op_name = sxp.name(req)
def op_console_disconnect(self, name, req):
id = sxp.child_value(req, 'id')
if not id:
- raise ValueError('Missing console id')
+ raise XendError('Missing console id')
self.daemon.console_disconnect(id)
return ['ok']
"""
ctrl = self.blkifCF.getInstanceByDom(dom)
if not ctrl:
- raise ValueError('No blkif controller: %d' % dom)
+ raise XendError('No blkif controller: %d' % dom)
print 'blkif_dev_create>', dom, vdev, mode, segment
d = ctrl.attachDevice(vdev, mode, segment, recreate=recreate)
return d
"""
ctrl = self.netifCF.getInstanceByDom(dom)
if not ctrl:
- raise ValueError('No netif controller: %d' % dom)
+ raise XendError('No netif controller: %d' % dom)
d = ctrl.attachDevice(vif, config, recreate=recreate)
return d
"""
console = self.get_console(id)
if not console:
- raise ValueError('Invalid console id')
+ raise XendError('Invalid console id')
console.disconnect()
def domain_shutdown(self, dom, reason):
"""
ctrl = self.domainCF.getInstanceByDom(dom)
if not ctrl:
- raise ValueError('No domain controller: %d' % dom)
+ raise XendError('No domain controller: %d' % dom)
ctrl.shutdown(reason)
return 0
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+from twisted.protocols import http
from twisted.web import error
+
from xen.xend import sxp
+from xen.xend.XendError import XendError
+
from SrvBase import SrvBase
+class SrvError(error.ErrorPage):
+
+ def render(self, request):
+ val = error.ErrorPage.render(self, request)
+ request.setResponseCode(self.code, self.brief)
+ return val
+
class SrvConstructor:
"""Delayed constructor for sub-servers.
Does not import the sub-server class or create the object until needed.
self.table = {}
self.order = []
+ def noChild(self, msg):
+ return SrvError(http.NOT_FOUND, msg, msg)
+
def getChild(self, x, req):
if x == '': return self
- val = self.get(x)
+ try:
+ val = self.get(x)
+ except XendError, ex:
+ return self.noChild(str(ex))
if val is None:
- return error.NoResource('Not found')
+ return self.noChild('Not found ' + str(x))
else:
return val
self.order.append(x)
def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-type", sxp.mime_type)
- self.ls(req, 1)
- else:
- req.write('<html><head></head><body>')
- self.print_path(req)
- self.ls(req)
- self.form(req)
- req.write('</body></html>')
- return ''
+ try:
+ if self.use_sxp(req):
+ req.setHeader("Content-type", sxp.mime_type)
+ self.ls(req, 1)
+ else:
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ self.ls(req)
+ self.form(req)
+ req.write('</body></html>')
+ return ''
+ except Exception, ex:
+ self._perform_err(ex, req)
def ls(self, req, use_sxp=0):
url = req.prePathURL()
self.xd = XendDmesg.instance()
def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(['dmesg'] + self.info(), out=req)
- else:
- req.write('<html><head></head><body>')
- req.write('<pre>')
- self.print_path(req)
- req.write(self.info()[0])
- req.write('</pre></body></html>')
- return ''
+ try:
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(['dmesg'] + self.info(), out=req)
+ else:
+ req.write('<html><head></head><body>')
+ req.write('<pre>')
+ self.print_path(req)
+ req.write(self.info()[0])
+ req.write('</pre></body></html>')
+ return ''
+ except Exception, ex:
+ self._perform_err(ex, req)
def info(self):
return self.xd.info()
fn = FormFn(self.xd.domain_device_create,
[['dom', 'int'],
['config', 'sxpr']])
- try:
- d = fn(req.args, {'dom': self.dom.id})
- d.addErrback(self._op_device_create_err, req)
- return d
- except ValueError, ex:
- return ['err', str(ex)]
-
- def _op_device_create_err(self, err, req):
- return ['err', str(err)]
+ d = fn(req.args, {'dom': self.dom.id})
+ return d
def op_device_destroy(self, op, req):
fn = FormFn(self.xd.domain_device_destroy,
from xen.xend import sxp
from xen.xend import XendDomain
from xen.xend.Args import FormFn
+from xen.xend.XendError import XendError
from SrvDir import SrvDir
from SrvDomain import SrvDomain
def domain(self, x):
val = None
- try:
- dom = self.xd.domain_get(x)
- if not dom: raise KeyError('No such domain')
- val = SrvDomain(dom)
- except KeyError, ex:
- print 'SrvDomainDir>', ex
- pass
+ dom = self.xd.domain_get(x)
+ if not dom:
+ raise XendError('No such domain ' + str(x))
+ val = SrvDomain(dom)
return val
def get(self, x):
Expects the domain config in request parameter 'config' in SXP format.
"""
ok = 0
+ errmsg = ''
try:
configstring = req.args.get('config')[0]
print 'config:', configstring
except Exception, ex:
print 'op_create> Exception in config', ex
traceback.print_exc()
+ errmsg = 'Configuration error ' + str(ex)
+ except sxp.ParseError, ex:
+ errmsg = 'Invalid configuration ' + str(ex)
if not ok:
- req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
- return "Invalid configuration"
- return error.ErrorPage(http.BAD_REQUEST,
- "Invalid",
- "Invalid configuration")
+ req.setResponseCode(http.BAD_REQUEST, errmsg)
+ return errmsg
try:
deferred = self.xd.domain_create(config)
deferred.addCallback(self._op_create_cb, configstring, req)
traceback.print_exc()
req.setResponseCode(http.BAD_REQUEST, "Error creating domain: " + str(ex))
return str(ex)
- #return error.ErrorPage(http.BAD_REQUEST,
- # "Error creating domain",
- # str(ex))
-
def _op_create_cb(self, dominfo, configstring, req):
"""Callback to handle deferred domain creation.
[['file', 'str']])
deferred = fn(req.args)
deferred.addCallback(self._op_restore_cb, req)
- deferred.addErrback(self._op_restore_err, req)
+ #deferred.addErrback(self._op_restore_err, req)
return deferred
def _op_restore_cb(self, dominfo, req):
return self.perform(req)
def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- self.ls_domain(req, 1)
- else:
- req.write("<html><head></head><body>")
- self.print_path(req)
- self.ls(req)
- self.ls_domain(req)
- self.form(req)
- req.write("</body></html>")
- return ''
+ try:
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ self.ls_domain(req, 1)
+ else:
+ req.write("<html><head></head><body>")
+ self.print_path(req)
+ self.ls(req)
+ self.ls_domain(req)
+ self.form(req)
+ req.write("</body></html>")
+ return ''
+ except Exception, ex:
+ self._perform_err(ex, req)
def ls_domain(self, req, use_sxp=0):
url = req.prePathURL()
return self.perform(req)
def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(['node'] + self.info(), out=req)
- else:
- url = req.prePathURL()
- if not url.endswith('/'):
- url += '/'
- req.write('<html><head></head><body>')
- self.print_path(req)
- req.write('<ul>')
- for d in self.info():
- req.write('<li> %10s: %s' % (d[0], str(d[1])))
- req.write('<li><a href="' +url + 'dmesg">Xen dmesg output</a>')
- req.write('</ul>')
- req.write('</body></html>')
- return ''
+ try:
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(['node'] + self.info(), out=req)
+ else:
+ url = req.prePathURL()
+ if not url.endswith('/'):
+ url += '/'
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ req.write('<ul>')
+ for d in self.info():
+ req.write('<li> %10s: %s' % (d[0], str(d[1])))
+ req.write('<li><a href="' + url + 'dmesg">Xen dmesg output</a>')
+ req.write('</ul>')
+ req.write('</body></html>')
+ return ''
+ except Exception, ex:
+ self._perform_err(ex, req)
def info(self):
return self.xn.info()
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+from xen.xend.XendError import XendError
+
import channel
import controller
from messages import *
"""
msgtype = self.reasons.get(reason)
if not msgtype:
- raise ValueError('invalid reason:' + reason)
+ raise XendError('invalid reason:' + reason)
msg = packMsg(msgtype, {})
self.writeRequest(msg)
from xen.xend import sxp
from xen.xend import PrettyPrint
from xen.xend import Vifctl
+from xen.xend.XendError import XendError
import channel
import controller
self.ipaddr = None
vmac = sxp.child_value(config, 'mac')
- if not vmac: raise ValueError("invalid mac")
+ if not vmac: raise XendError("invalid mac")
mac = [ int(x, 16) for x in vmac.split(':') ]
- if len(mac) != 6: raise ValueError("invalid mac")
+ if len(mac) != 6: raise XendError("invalid mac")
self.mac = mac
self.bridge = sxp.child_value(config, 'bridge')